#pragma once
#ifndef OBR_MIXEDMATERIAL_H
#define OBR_MIXEDMATERIAL_H

#include "common.h"
#include "core/Material.h"

namespace OBR
{
class Scene;

class MixedMaterial : public Material, public Configurable<MixedMaterial>
{
public:
    std::vector<std::shared_ptr<Material>> mat_list;
    std::vector<float> weights;

private:
    static std::shared_ptr<CudaProgram> program;
    static CudaBuffer sbt_data_payload;
    std::vector<uint> mat_ids;

public:
    MixedMaterial();
    ~MixedMaterial();

    /* ----------------------- override VirtualProgramEntry ----------------------- */

    /**
     * @brief upload all instances to payload
     *
     */
    void uploadVirtualProgramPayload(
        std::vector<std::shared_ptr<VirtualProgramEntry>> instances) override;

    /**
     * @brief Get the device ptr for this type of payload (one for each most derived type)
     *
     * @return CUdeviceptr
     */
    CUdeviceptr getPayloadDevicePtr() override;

    /* ------------------------ override ProgramEntry ----------------------- */

    /**
     * @brief Get the Program of this type
     *
     * @return std::shared_ptr<CudaProgram>
     */
    std::shared_ptr<CudaProgram> getProgram() override;

private:
    /* ------------------------ override ProgramEntry ----------------------- */

    /**
     * @brief Get the Program Group Options of this type
     *
     * @return OptixProgramGroupOptions&
     */
    OptixProgramGroupOptions &getProgramGroupOptions() override;

    /**
     * @brief Get the Program Group Desc of this type
     *
     * @return OptixProgramGroupOptions&
     */
    OptixProgramGroupDesc &getProgramGroupDesc() override;

    /**
     * @brief Set the Program for this type
     *
     * @param prog std::shared_ptr<CudaProgram>
     */
    void setProgram(std::shared_ptr<CudaProgram> prog) override;

protected:
    /* ------------------------ override Configurable ----------------------- */
    /**
     * @brief initialize object from config
     *
     * @param config
     */
    void _buildFromConfig(const Json::Value &config) override;

public:
    /**
     * @brief finalize object
     *
     * @param sc
     */
    void postBuild(Scene &sc) override;
};
} // namespace OBR
#endif
